package org.chameleon.datasource.manager;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.daojia.dconfig.client.DConfClient;
import com.daojia.dconfig.client.DConfHelper;
import com.daojia.dconfig.client.IDConfUpdateCallback;
import com.daojia.dconfig.client.common.exception.DConfClientException;
import com.daojia.dconfig.client.common.util.StringUtil;
import com.daojia.dconfig.client.dconf.SdkConfig;
import com.google.common.collect.Sets;
import org.apache.commons.lang3.StringUtils;
import org.chameleon.datasource.cache.CacheRefreshManager;
import org.chameleon.datasource.convert.Converter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * 抽象的jzConf配置管理
 *
 * @param <T>
 */
public abstract class AbsJzConfigManager<T> extends AbsConfigManager<T> implements IDConfUpdateCallback {


    private static final Logger LOGGER = LoggerFactory.getLogger(AbsJzConfigManager.class);


    private final String appName;

    /**
     * 对从配置中心拉取数据进行解析
     */
    private final Converter<String, T> converter;

    public AbsJzConfigManager(String appName, Converter<String, T> converter) {
        this.appName = appName;
        this.converter = converter;
        try {
            init();
        } catch (DConfClientException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取jzConf的group
     *
     * @param t
     * @return
     */
    public abstract String getGroup(T t);

    /**
     * 获取jzConf的key
     *
     * @param t
     * @return
     */
    public abstract String getKey(T t);

    @Override
    public T loadFromDateSource(T t) {
        try {
            final String group = getGroup(t);
            final String key = getKey(t);
            if (groupListenerNames.add(group)) {
                DConfClient.registerUpdateHandler(appName, group, this);
            }
            final String configFromJzConfig = this.getConfigFromJzConfig(group, key);
            LOGGER.debug("获取的 getDConfRateLimitDTO 配置信息为：{}", configFromJzConfig);
            if (!StringUtils.isBlank(configFromJzConfig)) {
                final T t1 = converter.doForward(buildRateLimit(appName,group,key,configFromJzConfig));
                return t1;
            }
        } catch (Exception e) {
            LOGGER.error("getDConfRateLimitDTO 异常", e);
        }
        return t;
    }

    private String getConfigFromJzConfig(String group, String key) {
        return DConfHelper.getConfigValue(appName, group, key);

    }

    private Map<String, String> getConfigFromJzConfig(String group) {
        return DConfHelper.getConfigInfo(appName, group);

    }


    /**
     * jzConf已经注册监听的回掉组
     */
    private static final Set<String> groupListenerNames = Sets.newConcurrentHashSet();


    private void init() throws DConfClientException  {
        if (isInit()) {
            LOGGER.info("JzConfConfig 未进行初始化 , 执行初始化流程");
            DConfClient.startDConfigManager(appName,"betaa","jzconfig-zktest1.service.djtest.cn:2181","https://jzconf.djtest.cn");
        }
        DConfClient.registerListenAppConfig(appName, true);

    }

    private boolean isInit() {
        return (StringUtil.isEmpty(SdkConfig.ENV_VALUE) || StringUtil.isEmpty(SdkConfig.APP_CLUSTER_VALUE) || StringUtil.isEmpty(SdkConfig.SERVER_API_DOMAIN_VALUE) || StringUtil.isEmpty(SdkConfig.ZK_ADDRESS_VALUE));
    }

    @Override
    public void callbackHandler(String appName, String group) {

        CacheRefreshManager.UPDATE_CONFIG_EXECUTOR.execute(() -> {
            Map<String, String> configFromJzConfigMap = getConfigFromJzConfig(group);
            Map<String, T> map = new LinkedHashMap<>();
            configFromJzConfigMap.keySet().forEach(key -> {
                final T t = converter.doForward(buildRateLimit(appName,group,key,configFromJzConfigMap.get(key)));
                map.put(buildCacheKey(t), t);
            });
            callBack(map);
        });
    }

    private String buildRateLimit(String appName,String group,String key,String config){
        final JSONObject jsonObject = JSON.parseObject(config);
        jsonObject.put("group",group);
        jsonObject.put("key",key);
        jsonObject.put("appName",appName);
        return jsonObject.toJSONString();
    }
}
